package com.zrx.govern.component.easyexcel.starter.utils;

import com.alibaba.excel.constant.BuiltinFormats;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zrx.govern.component.easyexcel.starter.constants.ExcelCheckConstants;
import com.zrx.govern.component.easyexcel.starter.config.ExcelConfigProperties;
import com.zrx.govern.component.easyexcel.starter.entity.*;
import com.zrx.govern.component.easyexcel.starter.entity.FieldRule;
import com.zrx.govern.component.easyexcel.starter.enums.FieldDataTypeEnum;
import com.zrx.govern.component.easyexcel.starter.enums.ImportType;
import com.zrx.govern.component.easyexcel.starter.enums.ValidEnum;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import static com.zrx.govern.component.easyexcel.starter.enums.ValidEnum.DICTIONARY_CHECK;

/**
 * 解析Json文件
 *
 * @author zhangxiaowei
 * @version V2.0
 */
public class JsonParseUtil {

    static Map<String, JSONObject> modelMap = new HashMap<>(6);
    static final String NUMBER = "NUMBER";
    static final String DATE = "DATE";
    static final List<String> DATEARR = Arrays.asList("yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM", "HH:mm:ss");
    static final List<String> NUMBERARR = Arrays.asList("0", "0.00", "#,##0", "#,##0.00","0.000");

    /**
     * 初始化加载json配置文件
     * @param excelConfigProperties
     */
    public static void initExcelSettingJson(ExcelConfigProperties excelConfigProperties){
        String path = "/" + excelConfigProperties.getTemplatePath() + "/" + excelConfigProperties.getJsonFile();
        Resource resource = new ClassPathResource(path);
        try {
            InputStream inputStream = resource.getInputStream();

            String content = new BufferedReader(
                    new InputStreamReader(inputStream, StandardCharsets.UTF_8)).lines()
                    .collect(Collectors.joining("\n"));
            JSONArray jsonArray = JSON.parseArray(content);
            jsonArray.forEach(obj -> {
                JSONObject jsonObject = (JSONObject) obj;
                if (Objects.isNull(jsonObject.get(ExcelCheckConstants.MODEL))) {
                    throw new RuntimeException("json文件model不能为空");
                }
                modelMap.put((String) jsonObject.get("model"), jsonObject);
            });
            inputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 根据业务获取Excel模板名字
     *
     * @param model 业务
     * @return string 模板名字
     */
    public static String getTemplateName(String model) {
        return (String) modelMap.get(model).get("excelTemplateName");
    }

    /**
     * 根据业务获取beanName
     *
     * @param model 业务
     * @return string 模板名字
     */
    public static String getBeanName(String model) {
        return (String) modelMap.get(model).get("beanName");
    }

    /**
     * 获取当前model对象所有field
     *
     * @param model
     * @return
     */
    public static List<ExcelField> getAllFields(String model) {
        List<ExcelField> fieldList = new ArrayList<>(8);
        if (!modelMap.containsKey(model)) {
            throw new RuntimeException(String.format("model不存在,请检查", model));
        }
        JSONArray fields = (JSONArray) modelMap.get(model).get("fields");
        List<String> fieldEnNames = new ArrayList<>(fields.size());
        fields.forEach(field -> {
            JSONObject jsonObject = (JSONObject) field;
            String fieldEnName = jsonObject.getString("fieldEnName");
            String fieldName = jsonObject.getString("fieldName");
            if (fieldEnNames.contains(fieldEnName)) {
                throw new RuntimeException(String.format("model:%s,field对象%s的字段fieldEnName出现重复,请检查!", model,fieldName));
            }
            Integer index = jsonObject.getInteger("index");
            Integer width = jsonObject.getInteger("width");
            String format = jsonObject.getString("format");
            String dataType = jsonObject.getString("dataType");
            if (StringUtils.isBlank(fieldEnName) || StringUtils.isBlank(fieldName)) {
                throw new RuntimeException(String.format("model:%s,field对象的字段fieldEnName或者fieldName不允许为空", model));
            }
            if (Objects.isNull(index)) {
                throw new RuntimeException(String.format("model:%s,field对象的字段index不允许为空", model));
            }
            fieldEnNames.add(fieldEnName);
            fieldList.add(ExcelField.builder().fieldEnName(fieldEnName).fieldName(fieldName).index(index).width(width).format(format).dataType(dataType).build());
        });
        /*排序*/
        fieldList.sort(Comparator.comparing(ExcelField::getIndex));
        /*添加fieldList的index是否连续的判断*/
        for (int i = 0; i < fieldList.size(); i++) {
            if (i != fieldList.get(i).getIndex()) {
                throw new RuntimeException(String.format("model:%s,field对象的字段index不连续,请检查!", model));
            }
        }
        /*校验field字段设置的format是否合法*/
        checkIsLegal(fieldList);
        return fieldList;
    }

    /**
     * 校验设置的format格式是否非法
     * @param fieldList
     */
    private static void checkIsLegal(List<ExcelField> fieldList) {
        /*校验field字段设置的format是否合法*/
        fieldList.stream().filter(el -> StringUtils.isNotBlank(el.getFormat())).forEach(el -> {
            if (DATEARR.contains(el.getFormat()) || NUMBERARR.contains(el.getFormat())) {
                if (StringUtils.isBlank(el.getDataType())) {
                    throw new RuntimeException(String.format("字段%s，dataType字段设置不允许为空!", el.getFieldEnName()));
                }
            }
            if (StringUtils.equalsIgnoreCase(DATE, el.getDataType())) {
                if (!DATEARR.contains(el.getFormat())) {
                    throw new RuntimeException(String.format("设置为DATE类型字段%s，format格式非法!", el.getFieldEnName()));
                }
            } else if (StringUtils.equalsIgnoreCase(NUMBER, el.getDataType())) {
                if (!NUMBERARR.contains(el.getFormat())) {
                    throw new RuntimeException(String.format("设置为NUMBER类型字段%s，format格式非法!", el.getFieldEnName()));
                }
            }else{
                if (!BuiltinFormats.BUILTIN_FORMATS_MAP_CN.containsKey(el.getFormat())) {
                    throw new RuntimeException(String.format("字段%s，format格式设置非法!", el.getFieldEnName()));
                }
            }
        });
    }


    /**
     * 获取数字字段设置的单元格格式
     * 参照excel右键设置的数字的单元格格式
     * @param list
     * @return
     */
    public static Map<Integer,FieldDataType> getFormatMap(List<ExcelField> list){
        Map<Integer, FieldDataType> map = new HashMap<>(4);
        /*校验*/
        checkIsLegal(list);
        list.stream().filter(el -> StringUtils.isNotBlank(el.getFormat())).forEach(el -> {
            FieldDataType fieldDataType = new FieldDataType().setFieldDataTypeEnum(FieldDataTypeEnum.getFieldDataTypeEnum(el.getDataType())).setFormat(el.getFormat());
            map.put(el.getIndex(), fieldDataType);
        });
        return map;
    }

    /**
     * 根据业务获取文件导入类型
     *
     * @param model 业务model
     * @return list
     */
    public static List<ImportType> getImportType(String model) {
        if (!modelMap.containsKey(model)) {
            throw new RuntimeException(String.format("model不存在,请检查", model));
        }
        JSONArray importType = (JSONArray) modelMap.get(model).get("importType");
        if (Objects.isNull(importType) || importType.isEmpty()) {
            throw new RuntimeException(String.format("model:%s,importType配置不允许为空,请检查", model));
        }
        return importType.toJavaList(ImportType.class);
    }


    /**
     * 获取具体字段与其字典值
     *
     * @param model 业务
     * @return map
     */
    public static Map<Integer, String> getDictionaries(String model) {
        Map<Integer, List<FieldRule>> fieldRules = getImportFieldRules(model);
        Map<Integer, String> dictionaries = new HashMap<>(2);
        fieldRules.keySet().forEach(index -> {
            List<FieldRule> list = fieldRules.get(index);
            list.forEach(fieldRule -> {
                if (fieldRule.getType().equals(DICTIONARY_CHECK)) {
                    dictionaries.put(index, fieldRule.getCode());
                }
            });
        });
        return dictionaries;
    }


    /**
     * 获取字段约束
     *
     * @param model 业务
     * @return map
     */
    public static Map<Integer, List<FieldRule>> getImportFieldRules(String model) {
        JSONArray fields = (JSONArray) modelMap.get(model).get("fields");
        Map<Integer, List<FieldRule>> ruleMap = new HashMap<>(6);
        List<Integer> validList = Arrays.stream(ValidEnum.values()).map(ValidEnum::getCode).collect(Collectors.toList());
        List<JSONObject> fieldJsonList = Lists.newArrayList();
        for (int i = 0; i < fields.size();i++) {
            JSONObject jsonObject = fields.getJSONObject(i);
            if (!Objects.isNull(jsonObject.get("index"))){
                fieldJsonList.add(jsonObject);
            }
        }
        fieldJsonList.forEach(jsonObject -> {
            Integer index = (Integer) jsonObject.get("index");
            JSONArray rules = (JSONArray) jsonObject.get("rules");
            String fieldName = jsonObject.getString("fieldName");
            List<FieldRule> fieldRuleList = new ArrayList<>();
            rules.forEach(rule -> {
                JSONObject ruleJson = (JSONObject) rule;
                if (!validList.contains(ruleJson.getInteger("type"))) {
                    throw new RuntimeException(String.format("字段%s配置的rules内type存在非法值,请检查", fieldName));
                }
                FieldRule fieldRule = JSONObject.parseObject(rule.toString(), FieldRule.class);
                fieldRuleList.add(fieldRule);
            });
            ruleMap.put(index, fieldRuleList);
        });
        return ruleMap;
    }

    /**
     * 获取联合校验字段集合
     *
     * @param model
     * @return list
     */
    public static List<UnionCheckField> getUnionUniqueFields(String model) {
        JSONArray jsonArray = (JSONArray) modelMap.get(model).get("unionCheckFields");
        if (Objects.nonNull(jsonArray)) {
            return jsonArray.toJavaList(UnionCheckField.class);
        }
        return new ArrayList<>();
    }


    /**
     * 获取
     * @param model
     * @return: com.zrx.govern.component.easyexcel.starter.entity.ExcelModel
     * @author zhangxiaowei
     **/
    public static ExcelModel getExcelModel(String model){
        JSONObject jsonObject = modelMap.get(model);
        if (Objects.nonNull(jsonObject)) {
            return jsonObject.toJavaObject(ExcelModel.class);
        }
        return null;
    }

    /**
     * 获取当前mode的持久化bean
     * @param model
     * @return
     */
    public static StorageBean getStorageBean(String model) {
        JSONObject jsonObject = (JSONObject) modelMap.get(model).get("storageBean");
        if (Objects.nonNull(jsonObject)) {
            return jsonObject.toJavaObject(StorageBean.class);
        }
        return null;
    }

}
